import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.ms.v20180408.MsClient;
import com.tencentcloudapi.ms.v20180408.models.CreateShieldInstanceRequest;
import com.tencentcloudapi.ms.v20180408.models.CreateShieldInstanceResponse;
import com.tencentcloudapi.ms.v20180408.models.DescribeShieldResultRequest;
import com.tencentcloudapi.ms.v20180408.models.DescribeShieldResultResponse;

import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;

//乐固加固方法
public class MyTest {
    private static Map<String, String> paramMap = new HashMap<String, String>();
    private static String saveApkPath = "";

    public static void main(String[] args) throws Exception {
        System.out.println("======Stephen============>开始执行腾讯乐固加固");
        if(null == args || args.length < 8 || isContainsParamKey(args[args.length - 1])){
            System.out.println("======Stephen============>乐固加固参数数据不足或格式错误，加固取消，请按此格式传递java -jar ms-shield.jar -sid xxxx -skey xxxx -uploadPath xxxx -downloadPath xxxx");
            return;
        }//end of if
        paramMap.clear();
        for(int i = 0; i < args.length; i++){
            System.out.println("======Stephen============>传递参数"+(i+1)+"："+args[i]);
            if("-sid".equals(args[i]) && !isContainsParamKey(args[i+1]))paramMap.put("-sid", args[i+1]);
            if("-skey".equals(args[i]) && !isContainsParamKey(args[i+1]))paramMap.put("-skey", args[i+1]);
            if("-uploadPath".equals(args[i]) && !isContainsParamKey(args[i+1]))paramMap.put("-uploadPath", args[i+1]);
            if("-downloadPath".equals(args[i]) && !isContainsParamKey(args[i+1]))paramMap.put("-downloadPath", args[i+1]);
        }//end of for
        if(paramMap.size() < 4){
            System.out.println("======Stephen============>乐固加固参数数据格式错误，加固取消，请按此格式传递java -jar ms-shield.jar -sid xxxx -skey xxxx -uploadPath xxxx -downloadPath xxxx");
            return;
        }//end of if
        String apkMa5Str = getFileMd5(paramMap.get("-uploadPath"));
        if(null == apkMa5Str || apkMa5Str.length() <= 0){
            System.out.println("======Stephen============>乐固加固生成Md5为空，加固取消");
            return;
        }//end of if
        saveApkPath = paramMap.get("-downloadPath");
        String uploadUrl = uploadApkFile(paramMap.get("-uploadPath"));
        System.out.println("======Stephen============>开始乐固加固:"+uploadUrl);
        String jiaGuApkPath = execTencentLeGuJiaGu(uploadUrl, apkMa5Str);
        boolean isJiaGuSuccess = null != jiaGuApkPath && jiaGuApkPath.length() > 0;
        System.out.println("======Stephen============>结束执行腾讯乐固加固，加固"+(isJiaGuSuccess ? "成功" : "失败")+"，jiaGuApkPath："+jiaGuApkPath);
    }

    private static boolean isContainsParamKey(String data){
        return "-sid".equals(data) || "-skey".equals(data) || "-uploadPath".equals(data) || "-downloadPath".equals(data);
    }

    public static String uploadApkFile(String filePath) {
        System.out.println("======Stephen============>开始上传待加固包:"+filePath);
        String fileSeparator = System.getProperty("file.separator");
        String fileName = filePath.substring(filePath.lastIndexOf(fileSeparator)+1);
        saveApkPath += (saveApkPath.endsWith(fileSeparator) ? "" : fileSeparator)+fileName.replace(".apk", "")+"_legu.apk";
        String endpoint = "oss-cn-hangzhou.aliyuncs.com";
        String accessKeyId = "xxxxx";
        String accessKeySecret = "xxxxxx";
        String bucketPath = "upgrade/appsafe/apk_tx/";
        String bucketName = "qy-static";
        String url = "https://static.qiyou.cn/upgrade/appsafe/apk_tx/"+fileName;
        File file = new File(filePath);
        OSS ossClient = new OSSClientBuilder().build("https://"+endpoint, accessKeyId, accessKeySecret);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, bucketPath+fileName, file);
        ossClient.putObject(putObjectRequest);
        ossClient.shutdown();
        System.out.println("======Stephen============>开始上传待加固包成功："+url);
        return url;
    }

    public static String execTencentLeGuJiaGu(String appHttpUrl, String appMd5){
        String itemId = null;
        try{
            Credential cred = new Credential(paramMap.get("-sid"),  paramMap.get("-skey"));
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("ms.tencentcloudapi.com");
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            MsClient client = new MsClient(cred, "", clientProfile);
            String params = "{\"AppInfo\":{\"AppUrl\":\""+appHttpUrl+"\",\"AppMd5\":\""+appMd5+"\"},\"ServiceInfo\":{\"ServiceEdition\":\"basic\",\"CallbackUrl\":\"\",\"SubmitSource\":\"MC\"}}";
            CreateShieldInstanceRequest req = CreateShieldInstanceRequest.fromJsonString(params, CreateShieldInstanceRequest.class);
            CreateShieldInstanceResponse resp = client.CreateShieldInstance(req);
            itemId = resp.getItemId();
            System.out.println("======Stephen============>乐固加固请求返回："+CreateShieldInstanceRequest.toJsonString(resp));
            System.out.println("======Stephen============>乐固加固请求的ItemId："+itemId);
        } catch (TencentCloudSDKException e) {
            System.out.println("======Stephen============>乐固加固请求异常："+e.toString());
        }
        if(null != itemId && itemId.length() > 0){
            String jiaGuAppUrl = getLeGuJiaGuResult(itemId);
            if(null == jiaGuAppUrl || jiaGuAppUrl.length() <= 0){
                System.out.println("======Stephen============>乐固加固完成Url为空，加固取消");
                return null;
            }//end of if
            File downloadFile = downloadForUrl(jiaGuAppUrl, saveApkPath);
            return null != downloadFile ? downloadFile.getAbsolutePath() : null;
        }else{
            System.out.println("======Stephen============>乐固加固请求itemId为空，加固取消");
        }
        return null;
    }

    public static String getLeGuJiaGuResult(String itemId) {
        long taskStatus = 2;//TaskStatus任务状态: 0-上传中待加固,1-已完成,2-处理中,3-处理出错,4-处理超时
        String apkUrl = "";//加固完成后apk的下载地址
        try{
            System.out.println("======Stephen============>乐固加固处理状态获取");
            DescribeShieldResultResponse resp = null;
            do {
                Credential cred = new Credential(paramMap.get("-sid"), paramMap.get("-skey"));
                HttpProfile httpProfile = new HttpProfile();
                httpProfile.setEndpoint("ms.tencentcloudapi.com");
                ClientProfile clientProfile = new ClientProfile();
                clientProfile.setHttpProfile(httpProfile);
                MsClient client = new MsClient(cred, "", clientProfile);
                String params = "{\"ItemId\":\""+itemId+"\"}";
                DescribeShieldResultRequest req = DescribeShieldResultRequest.fromJsonString(params, DescribeShieldResultRequest.class);
                resp = client.DescribeShieldResult(req);
                taskStatus = resp.getTaskStatus();
                switch ((int) taskStatus){
                    case 0: System.out.println("======Stephen============>乐固加固处理状态：上传中待加固");break;
                    case 1: System.out.println("======Stephen============>乐固加固处理状态：加固完成");break;
                    case 2: System.out.println("======Stephen============>乐固加固处理状态：加固中");break;
                    case 3: System.out.println("======Stephen============>乐固加固处理状态：加固出错");break;
                    case 4: System.out.println("======Stephen============>乐固加固处理状态：加固超时");break;
                    default: System.out.println("======Stephen============>乐固加固处理状态：未知");break;
                }//end of switch
            }while(taskStatus == 2||taskStatus == 0);
            System.out.println("======Stephen============>乐固加固处理返回："+DescribeShieldResultRequest.toJsonString(resp));
            if(taskStatus == 1){
                apkUrl = resp.getShieldInfo().getAppUrl();
                System.out.println("======Stephen============>乐固加固处理成功，apkUrl："+apkUrl);
            }//end of if
        } catch (TencentCloudSDKException e) {
            System.out.println("======Stephen============>乐固加固处理异常："+e.toString());
        }
        return apkUrl;
    }

    public static File downloadForUrl(String downloadUrl, String saveFilePath){
        System.out.println("======Stephen============>开始下载加固包："+downloadUrl+"===>存储位置："+saveFilePath);
        File file = new File(saveFilePath);
        if (!file.getParentFile().exists())file.getParentFile().mkdirs();
        FileOutputStream fileOut = null;
        HttpURLConnection conn = null;
        InputStream inputStream = null;
        try {
            System.out.println("======Stephen============>下载加固包中...");
            URL httpUrl=new URL(downloadUrl);
            conn=(HttpURLConnection) httpUrl.openConnection();
            conn.setRequestMethod("GET");
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.connect();
            inputStream=conn.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            fileOut = new FileOutputStream(saveFilePath);
            BufferedOutputStream bos = new BufferedOutputStream(fileOut);
            byte[] buf = new byte[4096];
            int length = bis.read(buf);
            while(length != -1) {
                bos.write(buf, 0, length);
                length = bis.read(buf);
            }//end of while
            bos.close();
            bis.close();
            conn.disconnect();
        } catch (Exception e) {
            file = null;
            System.out.println("======Stephen============>下载加固包异常："+e.toString());
        }
        return file;
    }

    public static String getFileMd5(String filePath){//获取app的md5
        System.out.println("======Stephen============>开始获取Apk的MD5："+filePath);
        String md5code = "";
        try {
            int FILE_READ_BUFFER_SIZE = 16 * 1024;
            MessageDigest digester = MessageDigest.getInstance("MD5");
            FileInputStream stream = new FileInputStream(filePath);
            int bytesRead;
            byte[] buf = new byte[FILE_READ_BUFFER_SIZE];
            while ((bytesRead = stream.read(buf)) >= 0) {
                digester.update(buf, 0, bytesRead);
            }//end of while
            md5code = new BigInteger(1, digester.digest()).toString(16);//16进制数字
            for (int i = 0; i < 32 - md5code.length(); i++)md5code = "0" + md5code;//如果生成数字未满32位，需要前面补0
            System.out.println("======Stephen============>获取到Apk的MD5："+md5code);
        }catch(Exception e){
            System.out.println("======Stephen============>获取Apk的MD5异常："+e.toString());
        }
        return md5code;
    }
}
